(ns pe.p17
  (:use pe.digits))

(def all-units ["" "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven"
  "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"])

(def all-tens ["" "ten" "twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety"])

(defn re-indexed [s] (map vector (iterate dec (count s)) s))

(defn tovector [s] (apply vector s))

(defn unit [n]
  {:pre [(>= n 0) (< n 20)]} (nth all-units n))

(defn ten [n]
  {:pre [(>= n 0) (< n 10) (not (= n 1))]} (nth all-tens n))

(def all-radix [
  #(unit %)
  #(ten %)
  (fn [x] (if (= x 0) "" (str (unit x) " hundred")))
  (fn [x] (if (= x 0) "" (str (unit x) " thousand")))])

(defn radix [n]
  {:pre [(> n 0) (< n 5)]} (nth all-radix (dec n)))

(defn rformat [x rad]
  (let [f (radix rad)]
    (f x)))

(defn norm-digits [n]
  (let [digs (tovector (reverse (re-indexed (digits n))))]
    (if (and (>= (count digs) 2) (= [2 1] (get digs 1)))
      (let [[idx val] (digs 0)]
        (assoc (assoc digs 1 [2 0]) 0 [idx (+ 10 val)]))
      digs)))

(defn word [n]
  (let [digs (norm-digits n)]
    (for [ab (reverse digs)] [(first ab) (rformat (last ab) (first ab))])))

(defn not-empty? [st] (not (= "" st)))

(defn add-and [w idx has-tens]
  (if (and (= idx 3) has-tens)
    (str w " and")
    w))

(defn wordize [n]
  (let [has-tens (< 0 (rem n 100))]
    (apply str (interpose " " (for [[idx w] (word n) :when (not-empty? w)] (add-and w idx has-tens))))))


(defn words [] (map last (iterate (fn [ab] [(inc (first ab)) (wordize (inc (first ab)))]) [1 "one"])))

(println (reduce #(+ %1 (count (filter (fn [x] (not (= \space x))) %2))) 0 (take 1000 (words))))
(println (wordize 342))
(println (count (filter #(not (= \space %)) (wordize 115))))